home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / System / ColourBlock CDEF ƒ / ColourBlock.c < prev    next >
C/C++ Source or Header  |  1994-01-18  |  13KB  |  552 lines

  1. /*    NAME:
  2.         ColourBlock.c
  3.  
  4.     WRITTEN BY:
  5.         Dair Grant
  6.         grantd@dcs.gla.ac.uk
  7.                 
  8.     DESCRIPTION:
  9.         A CDEF for getting a colour value from the user.
  10.  
  11.     ___________________________________________________________________________
  12.  
  13.     VERSION HISTORY:
  14.         1.0: (Jan 1994, dg)
  15.             •    First public release.
  16.  
  17.     ___________________________________________________________________________
  18. */
  19. //=============================================================================
  20. //        Include files                                                                     
  21. //-----------------------------------------------------------------------------
  22. #include <QuickDraw.h>
  23. #include "ColourBlock.h"
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30.  
  31. //=============================================================================
  32. //        Private defines                                                             
  33. //-----------------------------------------------------------------------------
  34. #define kBlockWidth            21                                // Width of colour block
  35. #define kBlockHeight        12                                // Height of colour block
  36. #define kTitleOffset        4                                // Offset of title
  37.  
  38.  
  39.  
  40.  
  41.  
  42.  
  43.  
  44. //=============================================================================
  45. //        Private function prototypes                                                                     
  46. //-----------------------------------------------------------------------------
  47. pascal long main(int theVarCode, ControlHandle theCntl, int theMsg, long theParam);
  48.  
  49. void        InitialiseMyControl(void);
  50. void        DisposeMyControl(void);
  51. long        TestMyControl(void);
  52. void        DrawMyControl(void);
  53. pascal void    DeviceLoopRoutine(short theDepth, short theFlags, GDHandle theDevice,
  54.                               Handle theHnd);
  55. RgnHandle    CalculateMyRegion(void);
  56. long        TrackMyControl(void);
  57.  
  58.  
  59.  
  60.  
  61.  
  62.  
  63.  
  64. //=============================================================================
  65. //        Global variables                                                                 
  66. //-----------------------------------------------------------------------------
  67. Boolean            gHasBeenCalled=false;                // Has the CDEF been called before?
  68. RGBColor        gFrameColour;                        // Colour of the control frame
  69. RGBColor        gTextColour;                        // Colour of the control text
  70. RGBColor        gBodyColour;                        // Fill colour for the control
  71. Rect            gTheColourRect;                        // Rectangle for the colour block
  72. Point            gTheTitlePt;                        // Point to draw the title on
  73.     
  74. int                gTheVarCode;                        // The varCode paramater
  75. ControlHandle    gTheCntl;                            // The theCntl paramater
  76. int                gTheMsg;                            // The theMsg paramater
  77. long            gTheParam;                            // The theParam paramater
  78.  
  79.  
  80.  
  81.  
  82.  
  83.  
  84.  
  85.  
  86.  
  87. //=============================================================================
  88. //        main : Entry point for the WDEF definition.
  89. //-----------------------------------------------------------------------------
  90. //        Note :    Basically we case out on theMsg and let other routines do the
  91. //                work.
  92. //-----------------------------------------------------------------------------
  93. pascal long main(int theVarCode, ControlHandle theCntl, int theMsg, long theParam)
  94. {    long retVal = 0L;
  95.  
  96.  
  97.  
  98.     // Set up A4 so we can have access to our globals
  99.     GetGlobals();
  100.     
  101.  
  102.     // Store the paramaters in globals for speed
  103.     gTheVarCode        = theVarCode;
  104.     gTheCntl        = theCntl;
  105.     gTheMsg            = theMsg;
  106.     gTheParam        = theParam;
  107.     
  108.     
  109.     // Case out on what we're meant to be doing
  110.     switch (theMsg) {
  111.         case initCntl:                    // Initialise our private data for this control
  112.             InitialiseMyControl();
  113.             break;
  114.         
  115.  
  116.         case dispCntl:                    // Dispose of our private data for this control
  117.             DisposeMyControl();
  118.             break;
  119.  
  120.  
  121.         case testCntl:                    // Test mouse to see if in control
  122.             retVal = TestMyControl();
  123.             break;
  124.         
  125.         
  126.         case drawCntl:                    // Draw the correct part of this control
  127.             DrawMyControl();
  128.             break;
  129.         
  130.         
  131.         case calcCRgns:                    // Calculate the draw region of this control
  132.         case calcCntlRgn:
  133.         case calcThumbRgn:
  134.             retVal = (long) CalculateMyRegion();
  135.             break;
  136.         
  137.         
  138.         case autoTrack:                    // Ignored messages
  139.         case posCntl:    
  140.         case thumbCntl:
  141.         case dragCntl:
  142.             break;
  143.         
  144.  
  145.         default:                        // Anything else
  146.             break;
  147.     }
  148.     
  149.  
  150.  
  151.  
  152.     // Restore A4 for our caller and return the result
  153.     UngetGlobals();
  154.     return(retVal);
  155. }
  156.  
  157.  
  158.  
  159.  
  160.  
  161.  
  162.  
  163.  
  164.  
  165.  
  166.  
  167. //=============================================================================
  168. //        InitialiseMyControl : Create a new instance of the control.
  169. //-----------------------------------------------------------------------------
  170. //        Note :    Allocate some private data and initialise a few variables,
  171. //                including auxillary colour.
  172. //-----------------------------------------------------------------------------
  173. void InitialiseMyControl(void)
  174. {    CDEFStructHnd    theCDEFDataHnd;
  175.     CDEFStructPtr    theCDEFDataPtr;
  176.     AuxCtlHandle    theAuxHnd;
  177.     CCTabHandle        theTableHnd;
  178.     
  179.     
  180.     
  181.     
  182.     
  183.     // If this is the first control this CDEF has created,
  184.     // we initialise some shared variables.
  185.     if (!gHasBeenCalled)
  186.         {
  187.         // We assume we have colour QuickDraw, and try and get the System colours
  188.         GetAuxCtl(gTheCntl, &theAuxHnd);
  189.         if (theAuxHnd)
  190.             {
  191.             // Lock the handle and dereference.
  192.             HLock(theAuxHnd);
  193.             theTableHnd = (*theAuxHnd)->acCTable;
  194.             
  195.             
  196.             // Copy the right colours
  197.             gFrameColour    = (*theTableHnd)->ctTable[cFrameColor].rgb; 
  198.             gTextColour        = (*theTableHnd)->ctTable[cTextColor].rgb;
  199.             gBodyColour        = (*theTableHnd)->ctTable[cBodyColor].rgb;
  200.             
  201.             
  202.             // Unlock the handle
  203.             HUnlock(theAuxHnd);
  204.             }
  205.         
  206.         
  207.         // If we couldn't get the colour table, we use some hardwired defaults
  208.         else
  209.             {
  210.             PackRGB(gFrameColour,    0x0000, 0x0000, 0x0000);
  211.             PackRGB(gTextColour,    0x0000, 0x0000, 0x0000);
  212.             PackRGB(gBodyColour,    0xFFFF, 0xFFFF, 0xFFFF);
  213.             }
  214.         
  215.         
  216.         // None of the above code needs to be done again
  217.         gHasBeenCalled = true;
  218.         }
  219.  
  220.  
  221.  
  222.     // Create some space for the control's data and initialise it.
  223.     theCDEFDataHnd = (CDEFStructHnd) NewHandle(sizeof(CDEFStruct));
  224.     if (theCDEFDataHnd)
  225.         {
  226.         // Start off white
  227.         PackRGB((*theCDEFDataHnd)->blockColour, 0xFFFF, 0xFFFF, 0xFFFF);
  228.         }
  229.  
  230.  
  231.     // Copy the handle into the control
  232.     (*gTheCntl)->contrlData = (Handle) theCDEFDataHnd;
  233. }
  234.  
  235.  
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243.  
  244.  
  245. //=============================================================================
  246. //        DisposeMyControl : Dispose of an instance of the control.
  247. //-----------------------------------------------------------------------------
  248. void DisposeMyControl(void)
  249. {
  250.  
  251.  
  252.     // If the control has a private data structure, dispose of it
  253.     if ((*gTheCntl)->contrlData)
  254.         DisposeHandle((*gTheCntl)->contrlData);
  255. }
  256.  
  257.  
  258.  
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267. //=============================================================================
  268. //        TestMyControl : Return the part code for a point.
  269. //-----------------------------------------------------------------------------
  270. //        Note :    This routine is used when a mousedown has occurred or a track
  271. //                is underway. We have to decide if a point is within our
  272. //                boundaries.
  273. //-----------------------------------------------------------------------------
  274. long TestMyControl(void)
  275. {    Point            testPoint;
  276.     long            retVal=0;
  277.     
  278.     
  279.     
  280.     // We only test if we're enabled
  281.     if ((*gTheCntl)->contrlHilite < 255)
  282.         {
  283.         // Convert the two coordinates to a point
  284.         testPoint.h = LoWord(gTheParam);
  285.         testPoint.v = HiWord(gTheParam);
  286.  
  287.     
  288.         // Return inCheckBox if it's in our control at all
  289.         if (PtInRect(testPoint, &(*gTheCntl)->contrlRect))
  290.             retVal = inCheckBox;
  291.         }
  292.  
  293.     
  294.     // Return the result
  295.     return(retVal);
  296. }
  297.  
  298.  
  299.  
  300.  
  301.  
  302.  
  303.  
  304.  
  305.  
  306.  
  307.  
  308. //=============================================================================
  309. //        DrawMyControl : Draw a part of a control.
  310. //-----------------------------------------------------------------------------
  311. //        Note :    We use DeviceLoop to call the actual drawing routine.
  312. //-----------------------------------------------------------------------------
  313. void DrawMyControl(void)
  314. {    int                center;
  315.     RGBColor        saveForeColour;
  316.     FontInfo        theFontInfo;
  317.  
  318.  
  319.  
  320.  
  321.     // Quick (and lazy) test to see if we've to do anything
  322.     if (!(*gTheCntl)->contrlVis)
  323.         return;
  324.         
  325.         
  326.     // Zap the high word of gTheParam
  327.     gTheParam = LoWord(gTheParam);
  328.     
  329.     
  330.     // The colour block is put on the left side of the control rectangle...
  331.     gTheColourRect            = (*gTheCntl)->contrlRect;
  332.     gTheColourRect.right    = gTheColourRect.left + kBlockWidth;
  333.     
  334.     // And centered vertically inside it...
  335.     center        = gTheColourRect.top + ((gTheColourRect.bottom - gTheColourRect.top) >> 1);
  336.     gTheColourRect.top        = center - (kBlockHeight >> 1);
  337.     gTheColourRect.bottom    = gTheColourRect.top + kBlockHeight;
  338.     
  339.  
  340.  
  341.     // The title is placed next to the colour block...
  342.     gTheTitlePt.h = gTheColourRect.right + kTitleOffset;
  343.  
  344.     // And centered vertically for the font size...    we have the center of
  345.     // the colour block, and we want to center the title on that.
  346.     GetFontInfo(&theFontInfo);
  347.     gTheTitlePt.v    = center + (theFontInfo.ascent >> 1) - 1;
  348.     
  349.  
  350.  
  351.     // Save the foreground colour
  352.     GetForeColor(&saveForeColour);
  353.  
  354.  
  355.     // Call the DeviceLoopRoutine with DeviceLoop to do the actual drawing.
  356.     DeviceLoop((*gTheCntl)->contrlOwner->visRgn,
  357.                (DeviceLoopDrawingProcPtr) DeviceLoopRoutine, 0, allDevices);
  358.  
  359.  
  360.     // Restore the foreground colour
  361.     RGBForeColor(&saveForeColour);
  362. }
  363.  
  364.  
  365.  
  366.  
  367.  
  368.  
  369.  
  370.  
  371.  
  372.  
  373.  
  374. //=============================================================================
  375. //        DeviceLoopRoutine : Called by DeviceLoop to do the drawing.
  376. //-----------------------------------------------------------------------------
  377. //        Note :    If we're disabled, we draw ourselves in a real gray if the
  378. //                device is deep enough, and a dithered gray otherwise.
  379. //-----------------------------------------------------------------------------
  380. pascal void DeviceLoopRoutine(short theDepth, short theFlags, GDHandle theDevice,
  381.                               Handle theHnd)
  382. {    RGBColor        blockColour, titleColour;
  383.     Rect            theColourRect;
  384.     CDEFStructHnd    theCDEFDataHnd;
  385.     Boolean            ditherText=false;
  386.  
  387.  
  388.  
  389.     // Draw what we're to draw
  390.     switch (gTheParam) {
  391.         case inCheckBox:                    // Draw/remove a selection from the block
  392.             // Set the draw colour
  393.             if ((*gTheCntl)->contrlHilite)
  394.                 RGBForeColor(&gFrameColour);
  395.             else
  396.                 RGBForeColor(&gBodyColour);
  397.  
  398.  
  399.             // Draw the selection rectangle
  400.             theColourRect = gTheColourRect;
  401.             InsetRect(&theColourRect, 1, 1);
  402.             FrameRect(&theColourRect);
  403.             break;
  404.         
  405.         
  406.         case 255:                            // Change in dimming
  407.         case 0:                                // Draw the entire control
  408.             // Draw the frame
  409.             theColourRect = gTheColourRect;
  410.             RGBForeColor(&gFrameColour);
  411.             FrameRect(&theColourRect);
  412.  
  413.  
  414.             // Draw the selection rectangle
  415.             RGBForeColor(&gBodyColour);
  416.             InsetRect(&theColourRect, 1, 1);
  417.             FrameRect(&theColourRect);
  418.  
  419.  
  420.             // The interior of the colour block and the title are
  421.             // coloured white and grey if the control is disabled.
  422.             // If we're on a mono display, we will dither the
  423.             // text if it's disabled.
  424.             if ((*gTheCntl)->contrlHilite == 255)
  425.                 {
  426.                 blockColour = gBodyColour;
  427.                 PackRGB(titleColour, 0x8000, 0x8000, 0x8000);
  428.                 
  429.                 if (theDepth == 1)
  430.                     ditherText = true;
  431.                 }
  432.             
  433.             
  434.             // Otherwise we use the normal colours.
  435.             else
  436.                 {
  437.                 theCDEFDataHnd    = (CDEFStructHnd) ((*gTheCntl)->contrlData);
  438.                 blockColour        = (*theCDEFDataHnd)->blockColour;
  439.                 titleColour        = gFrameColour;
  440.                 }
  441.                 
  442.             
  443.             // Draw the interior of the colour block
  444.             RGBForeColor(&blockColour);
  445.             InsetRect(&theColourRect, 1, 1);
  446.             PaintRect(&theColourRect);
  447.                         
  448.             
  449.             // Draw the title - switching to dithered text if in mono
  450.             RGBForeColor(&titleColour);
  451.             MoveTo(gTheTitlePt.h, gTheTitlePt.v);
  452.             if (ditherText)
  453.                 TextMode(grayishTextOr);
  454.             DrawString(&(*gTheCntl)->contrlTitle);
  455.             if (ditherText)
  456.                 TextMode(srcOr);
  457.             break;
  458.     }
  459. }
  460.  
  461.  
  462.  
  463.  
  464.  
  465.  
  466.  
  467.  
  468.  
  469.  
  470.  
  471. //=============================================================================
  472. //        CalculateMyRegion : Calculate the control's area region.
  473. //-----------------------------------------------------------------------------
  474. //        Note :    If we're running under 24-bit addressing, gTheMsg will be
  475. //                calcCRgns. Depending on the high bit of gTheParam we're
  476. //                then to calculate either the indicator region (bit is set)
  477. //                or the entire control (bit is not set).
  478. //
  479. //                Under 32-bit mode we can get sent either calcCntlRgn or
  480. //                calcThumbRgn messages.
  481. //
  482. //                We check first for the calcCRgns message, and fudge things
  483. //                so it turns into either a calcCntlRgn or a calcThumbRgn
  484. //                message.
  485. //-----------------------------------------------------------------------------
  486. RgnHandle CalculateMyRegion(void)
  487. {    RgnHandle    theRegion;
  488.     Rect        theRect;
  489.     int            theMsg;
  490.  
  491.  
  492.  
  493.  
  494.     // Cast the param to a RegionHandle
  495.     theRegion = (RgnHandle) gTheParam;
  496.     
  497.     
  498.     // If we're running under 24 bit addressing, find out which message we're
  499.     // meant to be doing.
  500.     if (gTheMsg == calcCRgns)
  501.         {
  502.         // If the high bit is set we're to calculate the indicator
  503.         if (0x80000000L & (long) theRegion)
  504.             theMsg = calcThumbRgn;
  505.             
  506.             
  507.         // Otherwise we're to calculate the entire control
  508.         else
  509.             theMsg = calcCntlRgn;
  510.             
  511.             
  512.         // Mask off the high bit from the region handle
  513.         theRegion = (RgnHandle) (0x7FFFFFFFL & (long) theRegion); 
  514.         }
  515.     else
  516.         theMsg == gTheMsg;
  517.     
  518.     
  519.  
  520.     // theMsg is either calcThumbRgn or calcCntl region, irrespective
  521.     // of 24 or 32 bit addressing. We handle it accordingly
  522.     theRect = (*gTheCntl)->contrlRect;
  523.     if (theMsg == calcThumbRgn)
  524.         {
  525.         // Calculate the indicator region
  526.         theRect = (*gTheCntl)->contrlRect;
  527.         theRect.right = theRect.left + kBlockWidth;
  528.         }
  529.     
  530.     // Calculate the entire control region
  531.     else
  532.         {
  533.         theRect = (*gTheCntl)->contrlRect;
  534.         }
  535.     
  536.     
  537.     
  538.     // Set theRegion to the rectangle
  539.     RectRgn(theRegion, &theRect);
  540.     
  541.     
  542.     
  543.     // See 'Control Manager Q&As' Tech note for why we return 1 if
  544.     // we were called under 32 bit mode.
  545.     if (gTheMsg != calcCRgns)
  546.         theRegion = (RgnHandle) 0x1L;
  547.         
  548.     
  549.     // Return the answer
  550.     return(theRegion);
  551. }
  552.